///////////////////////////////////////////////////////////////////////////////
///// Assignment 3: CPU Scheduler
///// By: Brady Robichaud (robicb82) & Patrick Filtz (filtzp43)
///// Date: 4/19/2013
///// File: SJFP.java
///// Description: This class deals with the shortest job first preemptive
/////	scheduler.
///////////////////////////////////////////////////////////////////////////////
package round2;

public class SJFP extends Queue{

	public SJFP(Process[] ps){
		this.ps = ps;
		
		for(int i = 0; i < ps.length; i++){
			psHash.put(ps[i].pID, ps[i]);
		}
		
		cpuRoot = cpuHead = new Node(false);
		cpuTail = cpuHead;
		
		ioRoot = ioHead = new Node(true);
		ioTail = ioHead;
		title = "_____________Shortest Job First Preemptive_____________";
	}
	
	public String run(){
		Process p;
		for(int time = 0; anyActive() ; time++){//time iteration loop
			for(int i = 0; i < ps.length; i++){//for each process
				p = ps[i];
				if(p.hasMore() && p.hasArrived(time) && p.burstReady){//if next burst is ready
					//add next burst to queue
					if(p.curIndex%2 == 0){
						addCPU(p);
						setProcReady(p.pID, false);
					}else{
						addIO(p);
						setProcReady(p.pID, false);
					}
				}
			}
			incrementWaits(cpuHead);
			incrementWaits(ioHead);
			
			if(cpuHead.waitNode){
				idleTime++;
			}else {
				cpuHead.curRemTime--;
				if(cpuHead.curRemTime <= 0){
					setProcReady(cpuHead.pID, true);
					psHash.get(cpuHead.pID).burstDone(time);
					psHash.get(cpuHead.pID).curIndex++;
					cpuHead = cpuHead.nextNode;
				}
			}
			
			if(!ioHead.waitNode){
				ioHead.curRemTime--;
				if(ioHead.curRemTime <= 0){
					setProcReady(ioHead.pID, true);
					psHash.get(ioHead.pID).burstDone(time);
					psHash.get(ioHead.pID).curIndex++;
					ioHead = ioHead.nextNode;
				}
			}
			
		}
		return getSummary(); //Prints queue and information to GUI
	}

	//Adds a new cpu node to the queue
	private void addCPU(Process p){
		Node newN = new Node(p.pID, p.bursts[p.curIndex], p.bursts[p.curIndex], false);
		if(cpuHead.waitNode){
			cpuHead.nextNode = newN;
			cpuHead = cpuHead.nextNode;
		}else{
			if(cpuHead.curRemTime > newN.curRemTime){
				Node headSecond = new Node(cpuHead.pID, cpuHead.curRemTime, cpuHead.curRemTime, false);
				cpuHead.duration -= cpuHead.curRemTime;
				cpuHead.curRemTime = 0;
				newN.nextNode = headSecond;
				headSecond.nextNode = cpuHead.nextNode;
				cpuHead.nextNode = newN;
				cpuHead = newN;
			}else{
				Node curNode = cpuHead;
				boolean cont = true;
				while(cont){
					if(curNode.nextNode.waitNode){
						curNode.nextNode = newN;
						cont = false;
					}else if(curNode.nextNode.curRemTime > newN.curRemTime){
						newN.nextNode = curNode.nextNode;
						curNode.nextNode = newN;
						cont = false;
					}else{
						curNode = curNode.nextNode;
					}
				}
			}
		}
	}	
}
